﻿using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Math;
using System;
using System.Text;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Math.EC;

namespace BlockchainCrypto
{
    class Sign
    {
        public static void Main()
        {
            var privateKey = "97ddae0f3a25b92268175400149d65d6887b9cefaf28ea2c078e05cdc15a3c0a";
            var d = new BigInteger(1, Hex.Decode(privateKey));
            var curve = ECNamedCurveTable.GetByName("secp256k1");
            var privateKeyParameters = new ECPrivateKeyParameters(d,
                new ECDomainParameters(curve.Curve, curve.G, curve.N));
            var signerAlgorithm = "SHA256withECDSA";

            ISigner signer = SignerUtilities.GetSigner(signerAlgorithm);
            signer.Init(true, privateKeyParameters);

            string msg = "Message for signing";
            byte[] msgBytes = Encoding.UTF8.GetBytes(msg);

            // keccak256 hash            
            var hashAlgorithm = new KeccakDigest(256);
            //byte[] input = last16BytesOfDerivedKey.ToArray();
            hashAlgorithm.BlockUpdate(msgBytes, 0, msgBytes.Length);

            byte[] data = new byte[32]; // 512 / 8 = 64
            hashAlgorithm.DoFinal(data, 0);

            signer.BlockUpdate(data, 0, data.Length);
            byte[] signature = signer.GenerateSignature();


            // verify signature
            signer = SignerUtilities.GetSigner(signerAlgorithm);
            //X9ECParameters curve = SecNamedCurves.GetByName("secp256k1");
            //var curve = ECNamedCurveTable.GetByName("secp256k1");

            //BigInteger d = new BigInteger(privateKey);
            ECPoint q = curve.G.Multiply(d);
            var publicKeyParameters = new ECPublicKeyParameters(q,
                new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H));
            signer.Init(false, publicKeyParameters);

            signer.BlockUpdate(data, 0, data.Length);
            if (signer.VerifySignature(signature))
                Console.WriteLine("verify success");
            //return signature;
        }
    }
}
